#!/opt/local/bin/python2.5
# $Id: netops.py 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy  <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

# Python imports
import os
import optparse
import sys
import shutil
import time
import hashlib

# Local imports
from ssn.tools import device
from ssn.tools import cmdparser
from ssn.tools import ip
from ssn.tools import log
# from ssn.tools import scm
# from ssn.tools import sql

__version__ = "$Revision: 7557b5d4d82b $"
__author__ = "$Author: pgurumur $"

class netops(cmdparser.GetOpt):
   """
   Subclass of GetOpt class from cmdparser
   This class backs up network configuration file, using TFTP/SNMP in case of
   IOS device, otherwise uses SSH

   1.init() for this class, just calls super
   """

   """
   Option list meta data, expands the default meta data from GetOpt class
   """
   option_list = (
         optparse.make_option("-a", "--add", action = "store_true",
            help = "Add SNMP information for a device", default = False,
            dest = "add"),
         optparse.make_option("-A", "--all", action = "store_true",
            help = "List devices in netdot", default = False,
            dest = "all"),
         optparse.make_option("-b", "--backup", action = "store_true",
            help = "Backup a device and update/add to subversion",
            default = False, dest = "backup"),
         optparse.make_option("-c", "--community", type = "str",
            help = "SNMP v1, v2c read/write community string",
            dest = "community"),
         optparse.make_option("-d", "--db", type = "str",
            help = "SQLite3 database to use",
            default = "/usr/ssn/etc/neteng.db", dest = "db"),
         optparse.make_option("-f", "--file", type = "str",
            help = "Script file to execute", dest = "file"),
         optparse.make_option("-l", "--list", action = "store_true",
            help = "List devices from netdot that will be backed up",
            default = False, dest = "devlist"),
         optparse.make_option("-L", "--login", action = "store_true",
            help = "Login to the device", default = False, dest = "login"),
         optparse.make_option("-p", "--pass", type = "str",
            help = "Password for SSH/Telnet", dest = "passwd"),
         optparse.make_option("-P", "--print", action = "store_true",
            help = "Print all/one device from SQLite database",
            default = False, dest = "devprint"),
         optparse.make_option("-r", "--remove", action = "store_true",
            help = "Remove SNMP information for a device", default = False,
            dest = "remove"),
         optparse.make_option("-s", "--site", type = "str",
            help = "List devices in netdot, belonging to a site",
            dest = "site"),
         optparse.make_option("-t", "--time", type = "int",
            help = "Time to wait for backup, default: 180", default = 180,
            dest = "time"),
         optparse.make_option("-T", "--tftp", type = "str",
            help = "TFTP server, used in case of static NAT", dest = "tftp"),
         optparse.make_option("-u", "--update", action = "store_true",
            help = "Update SNMP information for a device", default = False,
            dest = "update"),
         optparse.make_option("-U", "--user", type = "str",
            help = "Username for SSH/Telnet", dest = "user"),
   ) + cmdparser.GetOpt.option_list

   help = """
   SNMP/SSH based backup of Cisco devices using TFTP
   Devices are searched in netdot, using neteng.db located in /usr/ssn/etc/
   as the configuration for the program. Optionally, a single device
   configuration file can be retrieved. Device configuration files are backed
   up to svn repository

   -d/--db option can be specified to find where the SQLite database is
   located, default search location is the local directory

   If -T/--tftp option is used, the tftp server information will be used
   instead of the assuming that the server where this script is running as the
   TFTP server.

   If -A/--all option is listed, then this script will get the following details
   site, dns name, snmp commnunity product name, ip address and system descr
   from netdot device table

   If -s/--site option is listed, then this script will behave the same way as
   -A/--all option except it will list entries from that specific site alone
   """

   def __init__(self, **Keywords):
      """
      @brief init function that just calls super to instantiate the object
      @param self 'this' pointer for the class
      @param Keywords functional parameter for the class
      @return returns the object (subclass of GetOpt class)
      """
      self._query = None
      self._host = None
      self._tftp = None
      self._comm = None
      self._config = {}
      self._user = None
      self._pass = None
      self._file = None

      self.confdb = None
      self.netdb = None
      self.svn = None
      self.log = None
      self.login = None
      self.verbose = 0

      super(self.__class__, self).__init__(**Keywords)

   def getconfdict(self, Row):
      """
      @brief getconfdict function returns dictionary values of configuration
            sql row
      @param self 'this' pointer for the class
      @param Row SQL row obtained from the database
      @return dictionary value
      """

      config = {}
      if Row:
         config["from"] = Row[1]
         config["to"] = Row[2]
         config["sshuser"] = Row[3]
         config["sshpass"] = Row[4]
         config["sqluser"] = Row[5]
         config["sqldb"] = Row[6]
         config["sqlpass"] = Row[7]
         config["sqlhost"] = Row[8]
         config["svnhost"] = Row[9]
         config["svnuser"] = Row[10]
         config["svnpass"] = Row[11]
         config["loghost"] = Row[12]

      return config

   def mesgstr(self, Message):
      """
      @brief santize message string
      @param self 'this' pointer
      @param Message string
      @return string value
      """

      message = None
      if Message:
         if not isinstance(Message, str):
            message = str(Message)
         else:
            message = Message

      return message

   def write(self, Message):
      """
      @brief: Wrapper for print function"
      @param: self 'this' pointer for the class
      @param: Message, string that needs to be printed.
      @return: void function
      """
      print "%s: %s" %(str(self), self.mesgstr(Message))

   def SQLQuery(self, Query, NetEng = False, NetDot = False):
      """
      @brief: Given a query, either do query on neteng database or global
              netdot database
      @param: self 'this' pointer
      @param: Query, SQL query
      @param: NetEng, flag to indicate the query is for neteng database
      @param: NetDot, flag to indicate the query is for netdot database
      @retval: return value from the sql db as a row or list of rows
      """
      retval = []
      if Query:
         self.Log(Query)
         try:
            if NetEng:
               retval = self.confdb.Execute(Query)
            elif NetDot:
               retval = self.netdb.Execute(Query)
         except sql.SQLError, message:
            self.throw(message)

      return retval

   def throw(self, Message):
      """
      @brief throw exception (calls error function), but closes all the
             filehandles before throwing the error message
      @param self 'this' pointer for the class
      @param Message error message to be thrown
      @return None, void function
      """
      message = self.mesgstr(Message)

      if self.confdb:
         self.confdb.Close()

      if self.netdb:
         self.netdb.Close()

      if self.svn:
         self.svn.Close()

      if message:
         if self.log:
            self.log.critical(message)

         self.error(message)

      if self.login:
         self.login.Close()

   def Log(self, Message):
      """
      @brief: Log the message, based on the verbosity level
      @param: self 'this' pointer for the class
      @param: Message, message that needs to be logged
      @return: None, this is void function
      """
      message = self.mesgstr(Message)
      if message:
         if self.verbose:
            self.log.info(message)

         if self.verbose == 2:
            self.write(message)

   def _filedigest(self, File):
      """
      @brief: Get the SHA256 digest of a file, if the file is passed and file
              exists in the system, otherwise None value is returned.
      @param: self 'this' pointer for the class
      @param: File, as the name suggests, a file
      @return: Either digest or None value
      """

      digest = None
      if File:
         if os.path.exists(File):
            fh = None
            try:
               fh = open(File, "r")
            except IOError, message:
               self.throw(message)
            else:
               digest = hashlib.sha256(fh.read()).hexdigest()
            finally:
               fh.close()

      return digest

   def ConfigBackup(self, Time = None):
      """
      @brief: Function that does configuration backup to svn repository
      @param: self 'this' pointer for the class
      @return: None, this is a void function
      """

      # Get the subversion handle
      try:
         self.svn = scm.svn(username = self._config["svnuser"],
               password = self._config["svnpass"])
         self.svn.Client()
      except scm.SCMError, message:
         self.throw(message)

      revision = 0
      svndir = "/tmp/backups"

      # If svndir exists, remove it forcefully
      try:
         shutil.rmtree(svndir)
      except OSError, message:
         pass

      # Checkout the subversion tree for backups and lock it
      try:
         os.chdir("/tmp")
         revision = self.svn.checkout("backups", self._config["svnhost"])
      except scm.SCMError, message:
         self.throw(message)

      # Verify whether the subverion process created the directory
      try:
         os.stat(svndir)
      except OSError, message:
         self.throw(message)

      # Verify whether we have a revision number set to greater than zero
      if not revision:
         self.throw("SVN checkout cannot be at revision zero")

      self.Log("SVN revision for %s: %d" %(self._config["svnhost"], revision))

      # Determine whether host is given through the command line
      if self._host:
         hostip = None
         try:
            hostip = ip.ip(self._host)
            if hostip.size() > 1:
               self.throw("Cannot do backups, when a Network is defined!")
         except ip.IPError, message:
            self.throw(message)

         self._query += "where ipblock.address = '%d';" %int(hostip)

      # Based on whether we have a single host or if we are walking through
      # entire netdot, we query the netdot database to retrieve entry(ies)
      # and try to do a configuration backup for those entries/that entry
      sqlrow = self.SQLQuery(self._query, NetDot = True)
      deviceList = []   # Container to hold all the device class/threads
      for items in sqlrow:
         community = None
         tftp = None
         device_mon = items[0]
         device_id = items[1]
         device_name = items[2] + "." + items[3]
         device_type = items[4]
         device_ip = None

         # If the host is defined from the command line, the device_mon is
         # toggled to be True
         if self._host:
            device_mon = True

         # If community is defined from the command line, then the community
         # is used
         # CAREFUL: If community is defined, but no host is defined, then
         #          for every entry in the netdot, the given community string
         #          is used, not whatever is stored in the SQLite database
         if self._comm:
            community = self._comm

         try:
            device_ip = ip.ip(int(items[5]), version = 4)
         except ip.IPError, message:
            self.throw(message)
         except TypeError, message:
            self.throw(message)

         # Construct SQL query for retrieving the columns from device_snmp
         # table
         sqlQuery = None
         if community:
            sqlQuery = "select tftp from device_snmp "
         else:
            sqlQuery = "select snmp_rw, tftp from device_snmp "

         sqlQuery += "where device_name = \"%s\";" %device_name

         row = self.SQLQuery(sqlQuery, NetEng = True)
         if row:
            if not community:
               community = row[0][0]

            if self._tftp:
               tftp = self._tftp
            else:
               tftp = row[0][1]
               if tftp:
                  tftp = ip.ip(tftp, version = 4)

         if tftp:
            self.Log("tftpserver used for %s: %s" %(str(device_ip), str(tftp)))

         if community:
            self.Log("SNMP R/W community string for %s: %s" %(
               str(device_ip), community))

         devdict = {}
         devdict["loghost"] = self._config["loghost"]
         devdict["sshuser"] = self._config["sshuser"]
         devdict["sshpass"] = self._config["sshpass"]
         devdict["from"] = self._config["from"]
         devdict["to"] = self._config["to"]

         if self._user and self._pass:
            devdict["sshuser"] = self._user
            devdict["sshpass"] = self._pass
         elif self._user and not self._pass:
            devdict["sshuser"] = self._user
         elif self._pass and not self._user:
            devdict["sshpass"] = self._user
         else:
            sqlQuery = "select username, password from device_ssh "
            sqlQuery += "where device = %d;" %int(device_ip)
            row = self.SQLQuery(sqlQuery, NetEng = True)
            if row:
               if row[0][0]:
                  devdict["sshuser"] = row[0][0]

               if row[0][1]:
                  devdict["sshpass"] = row[0][1]

         self.Log("SSH username for %s is %s" %(
            str(device_ip), devdict["sshuser"]))

         device_descr = items[6]
         # If device_mon flag is on, then we retrieve the config from the
         # device
         if device_mon:
            dev = device.device(address = device_ip, name = device_name,
                  descr = device_descr, sleep = Time, community = community,
                  options = devdict, svndir = svndir, tftp = tftp,
                  verbose = self.verbose)
            deviceList.append(dev)
            dev.setName(device_name)
            dev.start()
            self.Log(dev)

      # Iterate through the container, waiting for the threads to stop
      for dev in deviceList:
         dev.join()

      # Iterate through the container, get the config and add/upate the config
      # to the subversion repository, also get the sha 256 digest of the file
      for dev in deviceList:
         config = dev.GetConfig()
         if config:
            digest = self._filedigest(config)
            date = time.strftime("%Y-%m-%d, %b %d %Y")
            svndict = self.svn.status(config)[0]
            mesg = "automatic checkin of %s on %s, SHA 256 digest: %s" %(
                  config, date, digest)
            if svndict.is_versioned:
               self.svn.CheckIn(config, mesg)
            else:
               self.svn.CheckIn(config, mesg, True)

            self.Log("config file for %s: %s, SHA 256 digest: %s" %(
               str(dev), config, digest))

      # Close subversion handle
      self.svn.Close()

      # rm -rf the subversion repository copy
      shutil.rmtree(svndir)

   def ModifyDatabase(self, Add = False, Update = False, Remove = False):
      """
      @brief: Add/Update/Remove devices from device_snmp and device_ssh
              SQLite database
      @param: self 'this' pointer for the class
      @return: Void function"
      """

      # If no host is defined in the cmdline and add/update/remove option is
      # used then, the script throws an error
      if not self._host:
         self.throw("no host defined!")

      self.Log("host given through command line: %s" %self._host)

      # Try to convert the host (string) to an ip object, if there was
      # any problem IPError exception is raised, causing this script to
      # error out.
      hostip = None
      try:
         hostip = ip.ip(self._host)
         if hostip.size() > 1:
            self.throw("Network defined instead of host address")
      except ip.IPError, message:
         self.throw(message)

      # Same as above, retrieve the values from netdot for the given 
      # device
      self._query += "where ipblock.address = %d;" %int(hostip)
      netrow = self.SQLQuery(self._query, NetDot = True)
      # If netdot returns empty, this script cannot proceed further
      if not netrow:
         self.throw("%s does not exist in netdot" %str(hostip))

      query = "select id from device_snmp where device = %d;" %int(hostip)
      row = self.SQLQuery(query, NetEng = True)
      if row:
         if Remove:
            query = "delete from device_snmp where device = %d;" %int(hostip)
            self.SQLQuery(query, NetEng = True)
            self.write("%s removed from device_snmp database" %str(hostip))
            self.Log("%s removed from device_snmp database" %str(hostip))
         elif Update:
            query = "update device_snmp "
            if self._comm and self._tftp:
               query += "set snmp_rw = \"%s\", tftp = %d where " %(
                     self._comm, self._tftp)
            elif self._comm and not self._tftp:
               query += "set snmp_rw = \"%s\" where " %self._comm
            elif self._tftp and not self._comm:
               query += "set tftp = %d where " %self._tftp
            else:
               query = None

            if query:
               query += "device = %d; " %int(hostip)
               self.SQLQuery(query, NetEng = True)
               self.write("%s updated in the device_snmp database" %str(hostip))
               self.Log("%s updated in the device_snmp database" %str(hostip))
         elif Add:
            self.write("%s already present in device_snmp database" %str(
               hostip))
            self.Log("%s already present in device_snmp database" %str(hostip))
      else:
         if Update or Remove:
            self.write("%s is not present in device_snmp database" %str(hostip))
         elif Add:
            name = netrow[0][2] + "." + netrow[0][3]
            query = "insert into device_snmp values (NULL, "
            if self._comm and self._tftp:
               query += "%d, \"%s\", \"%s\", %d);" %(
                     int(hostip), name, self._comm, int(self._tftp))
            elif self._comm and not self._tftp:
               query += "%d, \"%s\", \"%s\", 0);" %(
                           int(hostip), name, self._comm)
            else:
               query = None

            if query:
               self.SQLQuery(query, NetEng = True)
               self.write("%s added to device_snmp database" %str(hostip))
               self.Log("%s added to device_snmp database" %str(hostip))

      row = None
      query = "select id from device_ssh where device = %d;" %int(hostip)
      row = self.SQLQuery(query, NetEng = True)
      if row:
         if Update:
            query = "update device_ssh set "
            if self._user and self._pass:
               query += "username = \"%s\", " %self._user
               query += "password = \"%s\", " %self._pass
            elif self._user and not self._pass:
               query += "username = \"%s\", " %self._user
            elif self._pass and not self._user:
               query += "passwd = \"%s\", " %self._user
            else:
               query = None

            if query:
               query += "device = %d " %int(hostip)
               self.SQLQuery(query, NetEng = True)
               self.write("%s updated in the device_ssh database" %str(hostip))
               self.Log("%s updated in the device_ssh database" %str(hostip))
         elif Add:
            self.write("%s already present in device_ssh database" %str(
                  hostip))
            self.Log("%s already present in device_ssh database" %str(hostip))
         elif Remove:
            query = "delete from device_ssh where device = %d;" %int(hostip)
            self.SQLQuery(query, NetEng = True)
            self.write("%s removed from device_ssh database" %str(hostip))
            self.Log("%s removed from device_ssh database" %str(hostip))
      else:
         if Update or Remove:
            self.write("%s is not present in device_ssh database" %str(hostip))
         elif Add:
            query = "insert into device_ssh values (NULL, "
            if self._user and self._pass:
               query += "%d, \"%s\", \"%s\");" %(
                     int(hostip), self._user, self._pass)
            elif self._user and not self._pass:
               query += "%d, \"%s\", NULL);" %(int(hostip), self._user)
            elif self._pass and not self._user:
               query += "%d, NULL, \"%s\");" %(int(hostip), self._pass)
            else:
               query = None

            if query:
               self.SQLQuery(query, NetEng = True)
               self.write("%s added to device_ssh database" %str(hostip))
               self.Log("%s added to device_ssh database" %str(hostip))

   def PrintDevice(self, Site, Name, Comm, IP, Model = None):
      """
      @brief: Runner function to print
      @param: self 'this' pointer for the class
      @param: Site, data center site name
      @param: Name, name of the device
      @param: Comm: R/O community for the device
      @param: IP, IP address of the device
      @param: Model, optional, device model
      @return: Void function"
      """

      print "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
      print "Site: %s" %Site
      print "Name: %s" %Name
      print "SNMP R/O community: %s" %Comm
      if Model:
         print "Model: %s" %Model
      print "IP Address: %s" %IP
      print

   def GetDeviceList(self, Site = None, List = False):
      """
      @brief: Get device list from netdot
      @param: self 'this' pointer for the class
      @param: Site, data center site name
      @param: List, print devices that would be monitored
      @return: Void function"
      """

      query = "select site.name, device.id, rr.name, zone.mname, "
      query += "community, product.name, ipblock.address, sysdescription "
      if List:
         query += ", device.monitored "

      query += "from device "
      query += "left join site on site.id = device.site left join "
      query += "product on product.id = device.product left join "
      query += "ipblock on ipblock.id = device.snmp_target "
      query += "left join rr on rr.id = device.name "
      query += "left join zone on zone.id = rr.zone "

      if Site:
         query += "where site.name = '%s';" %Site
      else:
         query += ";"

      retval = self.SQLQuery(query, NetDot = True)
      total = len(retval)
      backCount = 0
      for items in retval:
         site = items[0]
         device_name = items[2] + "." + items[3]
         device_comm = items[4]
         device_model = items[5]
         device_ip = None
         device_mon = 0
         if List:
            device_mon = int(items[8])

         if items[6]:
            try:
               device_ip = ip.ip(int(items[6]), version = 4)
            except ip.IPError, message:
               self.write(message)

            if List:
               if device_mon:
                  self.PrintDevice(site, device_name, device_comm, device_ip)
                  backCount += 1
            else:
               self.PrintDevice(site, device_name, device_comm, device_ip,
                     device_model)
         else:
            self.throw("Invalid IP address for %s" %device_name)

      if not List:
         self.write("Total number of results: %d" %total)
      else:
         self.write("Total number of results: %d" %backCount)

   def GetLocalList(self):
      """
      @brief: Print local database entry/entries
      @param: self 'this' pointer for the class
      @return: Void function"
      """

      hostip = None
      if self._host:
         try:
            hostip = ip.ip(self._host)
         except ip.IPError, message:
            self.throw(message)

      query = "select * from device_snmp "
      if hostip:
         query += "where device = %d" %int(hostip)

      query += ";"

      print "SNMP table: "
      row = self.SQLQuery(query, NetEng = True)
      for items in row:
         tftp = None
         if not hostip:
            try:
               hostip = ip.ip(items[1], version = 4)
            except ip.IPError, message:
               self.throw(message)

         name = items[2]
         community = items[3]
         if items[4]:
            try:
               tftp = ip.ip(items[4], version = 4)
            except ip.IPError, message:
               self.throw(message)

         print "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
         print "Host: %s" %hostip
         print "Name: %s" %name
         print "Community: %s" %community
         if tftp:
            print "TFTP server: %s" %tftp

         print

         hostip = None

      print "---------------------------------------"

      query = "select * from device_ssh "
      if hostip:
         query += "where device = %d" %int(hostip)

      query += ";"

      print "SSH table: "
      row = self.SQLQuery(query, NetEng = True)
      for items in row:
         hostip = None
         try:
            hostip = ip.ip(int(items[1]), version = 4)
         except ip.IPError, message:
            self.throw(message)

         print "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
         print "Host: %s" %hostip
         print "Username: %s" %items[2]
         print

   def DeviceLogin(self):
      if self._file:
         try:
            self
      try:
         if self._host:
            if self._user:
               self.login = device.DeviceLogin(self._host, self._user)
            elif self._user and self._pass:
               self.login = device.DeviceLogin(
                     self._host, self._user, self._pass)
      except device.LoginError, message:
         self.throw(message)

      try:
         if self.login:
            if self._file:
               self.login.shell(self._file)
            else:
               self.login.shell()
      except device.LoginError, message:
         self.throw(message)
      finally:
         if self.login:
            self.login.Close()

   def handle(self):
      """
      @brief Do the actual work of processing the options and dealing with
             backups, adding/updating entries to database, listing devices from
             netdot, listing devices from local config database
      @param self 'this' pointer for the class
      @return None, void function
      """
      # Parse the command line
      (options, args) = self.parse()
      self._config = {}
      self._tftp = None
      self.verbose = int(options.verbosity)

      # -u option, -a option and -b option are supposed to be use exclusively
      # cannot be used in combination
      if options.update and options.add:
         self.error(
               "Cannot process both update and add options at the same time")
      elif options.update and options.backup:
         self.error(
               "Cannot process both update and backup options at the same time")
      elif options.backup and options.add:
         self.error(
               "Cannot process both backup and add options at the same time")
      elif options.all and options.site:
         self.error(
               "Cannot process both all and site options at the same time")
      elif options.remove and options.add:
         self.error(
               "Cannot process both remove and add options at the same time")
      elif options.remove and options.backup:
         self.error(
               "Cannot process both remove and backup options at the same time")
      elif options.remove and options.update:
         self.error(
               "Cannot process both remove and update options at the same time")

      """
      Master query used for add, update, backup options
      Retrieves id, device name, zone name, product information,
      IP address and system description from netdot
      """

      self._query = "select device.monitored, device.id, rr.name, zone.mname, "
      self._query += "product.name, ipblock.address, sysdescription "
      self._query += "from device "
      self._query += "left join product on product.id = device.product "
      self._query += "left join ipblock on ipblock.id = device.snmp_target "
      self._query += "left join rr on rr.id = device.name "
      self._query += "left join zone on zone.id = rr.zone "

      # Local SQLlite configuration database handle"
      self.confdb = None

      # Remote Netdot database handle
      self.netdb = None

      if options.community:
         self._comm = options.community.strip()

      if options.user:
         self._user = options.user.strip()

      if options.passwd:
         self._pass = options.passwd.strip()

      if options.file:
         self._file = options.file.strip()

      # In case of Static NAT, the tftp server discovery process would fail,
      # since the NAT'ed IP address is something that cannot be auto discover
      # In that case, the tftp server address needs to be present in the DB
      # for the backup to happen
      if options.tftp:
         try:
            temp = ip.ip(options.tftp)
            if temp.size() > 1:
               self.error("TFTP server is defined as a network!")

            self._tftp = temp
         except ip.IPError, message:
            self.error(message)

      # Determine whether we have host defined!, if args[1] is not present
      # then we get an IndexError
      self._host = None
      try:
         self._host = args[1]
      except IndexError, message:
         pass

      if options.login or options.file:
         self.DeviceLogin()
      else:
         if os.getuid() != 0:
            if not (options.all or options.site or options.devlist or
                  options.devprint):
               self.error("needs to be run as root!")

         if options.db:
            # Get the handle for local SQLite configuration database
            try:
               self.confdb = sql.sqlite(options.db)
            except sql.SQLError, message:
               self.error(message)

            # Retrieve the data from config_backup table and
            # use just the first row
            sqlQuery = "select * from config_backup;"
            sqlrow = []
            try:
               sqlrow = self.confdb.Execute(sqlQuery)
            except sql.SQLError, message:
               self.error(message)

            # Get all the configuration parameters as a dictionary value
            self._config = self.getconfdict(sqlrow[0])
            self.log = log.Log(str(self), self._config["loghost"])

            # Using the dictionary value, get a MySQL handle to netdot
            try:
               self.netdb = sql.mysql(self._config["sqldb"],
                     self._config["sqlhost"], self._config["sqluser"],
                     self._config["sqlpass"])
            except sql.SQLError, message:
               self.throw(message)
         else:
            self.error("database is not defined, cannot proceed further!")

         # Process Options
         if options.add:
            self.ModifyDatabase(Add = True)
         elif options.update:
            self.ModifyDatabase(Update = True)
         elif options.remove:
            self.ModifyDatabase(Remove = True)
         elif options.backup:
            self.ConfigBackup(options.time)
         elif options.all or options.site or options.devlist:
            self.GetDeviceList(Site = options.site, List = options.devlist)
         elif options.devprint:
            self.GetLocalList()
         else:
            self.printhelp()

         self.confdb.Close()
         self.netdb.Close()

# If the namespace is main
if __name__ == "__main__":
   # Construct the backup command line options
   netopt = None
   try:
      netopt = netops(version = 6.2, args = sys.argv, usage = "[ host ]")
      if len(netopt) <= 1:
         netopt.printhelp()
      else:
         netopt.handle()
   except cmdparser.GetOptError, message:
      print message
      sys.exit(1)
